From 707d5ae99c3a3c811d8c87b70a680aaa5d6e6398 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 21 Apr 2010 01:46:52 +0200 Subject: [PATCH] GtkCssProvider: Parse named regions. --- gtk/gtkcssprovider.c | 115 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c index 039f4a0f09..394c74e6ee 100644 --- a/gtk/gtkcssprovider.c +++ b/gtk/gtkcssprovider.c @@ -35,6 +35,7 @@ typedef struct SelectorStyleInfo SelectorStyleInfo; typedef enum SelectorElementType SelectorElementType; typedef enum CombinatorType CombinatorType; typedef enum ParserScope ParserScope; +typedef enum ParserSymbol ParserSymbol; enum SelectorElementType { SELECTOR_TYPE_NAME, @@ -87,10 +88,27 @@ struct GtkCssProviderPrivate enum ParserScope { SCOPE_SELECTOR, SCOPE_PSEUDO_CLASS, + SCOPE_NTH_CHILD, SCOPE_DECLARATION, SCOPE_VALUE }; +/* Extend GtkStateType, since these + * values are also used as symbols + */ +enum ParserSymbol { + /* Scope: pseudo-class */ + SYMBOL_NTH_CHILD = GTK_STATE_LAST, + SYMBOL_FIRST_CHILD, + SYMBOL_LAST_CHILD, + + /* Scope: nth-child */ + SYMBOL_NTH_CHILD_EVEN, + SYMBOL_NTH_CHILD_ODD, + SYMBOL_NTH_CHILD_FIRST, + SYMBOL_NTH_CHILD_LAST +}; + #define GTK_CSS_PROVIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_CSS_PROVIDER, GtkCssProviderPrivate)) static void gtk_css_provider_finalize (GObject *object); @@ -257,6 +275,15 @@ gtk_css_provider_init (GtkCssProvider *css_provider) g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "selected", GUINT_TO_POINTER (GTK_STATE_SELECTED)); g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "insensitive", GUINT_TO_POINTER (GTK_STATE_INSENSITIVE)); + g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "nth-child", GUINT_TO_POINTER (SYMBOL_NTH_CHILD)); + g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "first-child", GUINT_TO_POINTER (SYMBOL_FIRST_CHILD)); + g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "last-child", GUINT_TO_POINTER (SYMBOL_LAST_CHILD)); + + g_scanner_scope_add_symbol (scanner, SCOPE_NTH_CHILD, "even", GUINT_TO_POINTER (SYMBOL_NTH_CHILD_EVEN)); + g_scanner_scope_add_symbol (scanner, SCOPE_NTH_CHILD, "odd", GUINT_TO_POINTER (SYMBOL_NTH_CHILD_ODD)); + g_scanner_scope_add_symbol (scanner, SCOPE_NTH_CHILD, "first", GUINT_TO_POINTER (SYMBOL_NTH_CHILD_FIRST)); + g_scanner_scope_add_symbol (scanner, SCOPE_NTH_CHILD, "last", GUINT_TO_POINTER (SYMBOL_NTH_CHILD_LAST)); + priv->scanner = scanner; css_provider_apply_scope (css_provider, SCOPE_SELECTOR); } @@ -623,6 +650,73 @@ css_provider_commit (GtkCssProvider *css_provider) } } +static GTokenType +parse_nth_child (GtkCssProvider *css_provider, + GScanner *scanner, + SelectorPath *selector, + GtkChildClassFlags *flags) +{ + ParserSymbol symbol; + + *flags = 0; + + css_provider_push_scope (css_provider, SCOPE_PSEUDO_CLASS); + g_scanner_get_next_token (scanner); + + if (scanner->token != G_TOKEN_SYMBOL) + return G_TOKEN_SYMBOL; + + symbol = GPOINTER_TO_INT (scanner->value.v_symbol); + + if (symbol == SYMBOL_NTH_CHILD) + { + g_scanner_get_next_token (scanner); + + if (scanner->token != G_TOKEN_LEFT_PAREN) + return G_TOKEN_LEFT_PAREN; + + css_provider_push_scope (css_provider, SCOPE_NTH_CHILD); + g_scanner_get_next_token (scanner); + + if (scanner->token != G_TOKEN_SYMBOL) + return G_TOKEN_SYMBOL; + + symbol = GPOINTER_TO_INT (scanner->value.v_symbol); + + switch (symbol) + { + case SYMBOL_NTH_CHILD_EVEN: + *flags = GTK_CHILD_CLASS_EVEN; + break; + case SYMBOL_NTH_CHILD_ODD: + *flags = GTK_CHILD_CLASS_ODD; + break; + case SYMBOL_NTH_CHILD_FIRST: + *flags = GTK_CHILD_CLASS_FIRST; + break; + case SYMBOL_NTH_CHILD_LAST: + *flags = GTK_CHILD_CLASS_LAST; + break; + default: + break; + } + + g_scanner_get_next_token (scanner); + + if (scanner->token != G_TOKEN_RIGHT_PAREN) + return G_TOKEN_RIGHT_PAREN; + + css_provider_pop_scope (css_provider); + } + else if (symbol == SYMBOL_FIRST_CHILD) + *flags = GTK_CHILD_CLASS_FIRST; + else if (symbol == SYMBOL_LAST_CHILD) + *flags = GTK_CHILD_CLASS_LAST; + + css_provider_pop_scope (css_provider); + return G_TOKEN_NONE; +} + static GTokenType parse_selector (GtkCssProvider *css_provider, GScanner *scanner, @@ -642,6 +736,23 @@ parse_selector (GtkCssProvider *css_provider, { if (g_ascii_isupper (scanner->value.v_identifier[0])) selector_path_prepend_type (path, scanner->value.v_identifier); + else if (g_ascii_islower (scanner->value.v_identifier[0])) + { + GtkChildClassFlags flags = 0; + + /* Parse nth-child type pseudo-class */ + if (g_scanner_peek_next_token (scanner) == ':') + { + GTokenType token; + g_scanner_get_next_token (scanner); + + if ((token = parse_nth_child (css_provider, scanner, path, &flags)) != G_TOKEN_NONE) + { + selector_path_unref (path); + return token; + } + } + } else if (scanner->value.v_identifier[0] == '*') selector_path_prepend_glob (path); else @@ -723,9 +834,7 @@ parse_value (GType type, return TRUE; } else - { - g_warning ("Cannot parse string '%s' for type %s", value_str, g_type_name (type)); - } + g_warning ("Cannot parse string '%s' for type %s", value_str, g_type_name (type)); return FALSE; } -- 2.30.2